home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / zcpp_jae.zip / CPP3.C < prev    next >
C/C++ Source or Header  |  1991-05-18  |  15KB  |  571 lines

  1. /*
  2.  
  3.  
  4.  Copyright (C) 1990 Texas Instruments Incorporated.
  5.  
  6.  Permission is granted to any individual or institution to use, copy, modify,
  7.  and distribute this software, provided that this complete copyright and
  8.  permission notice is maintained, intact, in all copies and supporting
  9.  documentation.
  10.  
  11.  Texas Instruments Incorporated provides this software "as is" without
  12.  express or implied warranty.
  13.  
  14.  
  15.  *                C P P 3 . C
  16.  *
  17.  *            File open and command line options
  18.  *
  19.  * Edit history
  20.  * 13-Nov-84    MM    Split from cpp1.c
  21.  * 21-Oct-85    rms    Make -g command arg not cause an error.
  22.  * 24-Sep-89    AFM     OS2 and XENIX support.
  23.  * 19-Jan-90    DKM     MVS support.
  24.  * 18-May-90    MBN     Conditional compilation for COOL to get "clean" cpp
  25.  * 27-Apr-91    gcg     Added conditional compilation of __STDC__ define.
  26.  * 18-May-91    dle     Import INCLUDE from environment for DOS/OS2.
  27.  *            Added -A switch for conditional __STDC__ define.
  28.  *            Added -m switch for DOS/OS2 memory models.
  29.  */
  30.  
  31.  
  32. #include    <stdio.h>
  33. #include    <ctype.h>
  34. #include    <time.h>
  35. #include    "cppdef.h"
  36. #include    "cpp.h"
  37.  
  38. /* The type returned from time is double on MVS, long everywhere else.
  39.  * MVS defines this type as time_t.   Add non MVS definition here.
  40.  */
  41. #if HOST != SYS_MVS
  42. #define  time_t long
  43. #endif
  44.  
  45. #if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX || HOST == SYS_XENIX || HOST == SYS_OS2 || HOST == SYS_MVS)
  46. #include    <signal.h>
  47. extern int    abort();        /* For debugging        */
  48. #endif
  49.  
  50. extern void expand_line();
  51. extern void expand_file();
  52.  
  53. #ifdef COOL
  54. extern void define_package();       /* Define a new symbol package */
  55. #endif
  56.  
  57. int
  58. openfile(filename)
  59. char        *filename;
  60. /*
  61.  * Open a file, add it to the linked list of open files.
  62.  * This is called only from doinclude().
  63.  */
  64. {
  65.     register FILE        *fp;
  66.  
  67.     if ((fp = fopen(filename, "r")) == NULL) {
  68. #if DEBUG
  69.         perror(filename);
  70. #endif
  71.         return (FALSE);
  72.     }
  73. #if DEBUG
  74.     if (debug)
  75.         fprintf(stderr, "Reading from \"%s\"\n", filename);
  76. #endif
  77.     addfile(fp, filename);
  78.     return (TRUE);
  79. }
  80.  
  81. addfile(fp, filename)
  82. FILE        *fp;            /* Open file pointer        */
  83. char        *filename;        /* Name of the file        */
  84. /*
  85.  * Initialize tables for this open file.  This is called from openfile()
  86.  * above (for #include files), and from the entry to cpp to open the main
  87.  * input file.  It calls a common routine, getfile() to build the FILEINFO
  88.  * structure which is used to read characters.  (getfile() is also called
  89.  * to setup a macro replacement.)
  90.  */
  91. {
  92.     register FILEINFO    *file;
  93.     extern FILEINFO        *getfile();
  94.  
  95.     file = getfile(NBUFF, filename);
  96.     file->fp = fp;            /* Better remember FILE *    */
  97.     file->buffer[0] = EOS;        /* Initialize for first read    */
  98.     line = 1;            /* Working on line 1 now    */
  99.     wrongline = TRUE;        /* Force out initial #line    */
  100. }
  101.  
  102. setincdirs()
  103. /*
  104.  * Append system-specific directories to the include directory list.
  105.  * Called only when cpp is started.
  106.  */
  107. {
  108.  
  109. #ifdef    CPP_INCLUDE
  110.     *incend++ = CPP_INCLUDE;
  111. #define    IS_INCLUDE    1
  112. #else
  113. #define    IS_INCLUDE    0
  114. #endif
  115.  
  116. #if (HOST == SYS_UNIX || HOST == SYS_XENIX)
  117.     *incend++ = "/usr/include";
  118. #define    MAXINCLUDE    (NINCLUDE - 1 - IS_INCLUDE)
  119. #endif
  120.  
  121. #if HOST == SYS_OS2
  122.     {
  123.         extern char *getenv();
  124.         extern char *strtok();
  125.  
  126.         char *cp = getenv("INCLUDE");
  127.  
  128.         if (cp != NULL)
  129.             for (cp = strtok(cp, ";"); cp != NULL; cp = strtok(NULL, ";"))
  130.                 *incend++ = cp;
  131.     }
  132. #define    MAXINCLUDE    (NINCLUDE - 1 - IS_INCLUDE)
  133. #endif
  134.  
  135. #if HOST == SYS_MVS
  136. /* MVS will not use the include list via the -I option.  Instead
  137.  * logical ddnames are allocated to a concatenation of include
  138.  * libraries.  Specifying -I for mvs will be an error.
  139.  */
  140. #define    MAXINCLUDE    0
  141. #endif
  142.  
  143. #if HOST == SYS_VMS
  144.     extern char    *getenv();
  145.  
  146.     if (getenv("C$LIBRARY") != NULL)
  147.         *incend++ = "C$LIBRARY:";
  148.     *incend++ = "SYS$LIBRARY:";
  149. #define    MAXINCLUDE    (NINCLUDE - 2 - IS_INCLUDE)
  150. #endif
  151.  
  152. #if HOST == SYS_RSX
  153.     extern int    $$rsts;            /* TRUE on RSTS/E    */
  154.     extern int    $$pos;            /* TRUE on PRO-350 P/OS    */
  155.     extern int    $$vms;            /* TRUE on VMS compat.    */
  156.  
  157.     if ($$pos) {                /* P/OS?        */
  158.         *incend++ = "SY:[ZZDECUSC]";    /* C #includes        */
  159.         *incend++ = "LB:[1,5]";        /* RSX library        */
  160.     }
  161.     else if ($$rsts) {            /* RSTS/E?        */
  162.         *incend++ = "SY:@";            /* User-defined account    */
  163.         *incend++ = "C:";            /* Decus-C library    */
  164.         *incend++ = "LB:[1,1]";        /* RSX library        */
  165.     }
  166.     else if ($$vms) {            /* VMS compatibility?    */
  167.         *incend++ = "C:";
  168.     }
  169.     else {                    /* Plain old RSX/IAS    */
  170.         *incend++ = "LB:[1,1]";
  171.     }
  172. #define    MAXINCLUDE    (NINCLUDE - 3 - IS_INCLUDE)
  173. #endif
  174.  
  175. #if HOST == SYS_RT11
  176.     extern int    $$rsts;            /* RSTS/E emulation?    */
  177.  
  178.     if ($$rsts)
  179.         *incend++ = "SY:@";            /* User-defined account    */
  180.     *incend++ = "C:";            /* Decus-C library disk    */
  181.     *incend++ = "SY:";            /* System (boot) disk    */
  182. #define    MAXINCLUDE    (NINCLUDE - 3 - IS_INCLUDE)
  183. #endif
  184. }
  185.  
  186. int
  187. dooptions(argc, argv)
  188. int        argc;
  189. char        *argv[];
  190. /*
  191.  * dooptions is called to process command line arguments (-Detc).
  192.  * It is called only at cpp startup.
  193.  */
  194. {
  195.     register char        *ap;
  196.     register DEFBUF        *dp;
  197.     register int        c;
  198.     int            i, j;
  199.     char            *arg;
  200.     SIZES            *sizp;        /* For -S        */
  201.     int            size;        /* For -S        */
  202.     int            isdatum;    /* FALSE for -S*    */
  203.     int            endtest;    /* For -S        */
  204.  
  205.     for (i = j = 1; i < argc; i++) {
  206.         arg = ap = argv[i];
  207.         if (*ap++ != '-' || *ap == EOS)
  208.         argv[j++] = argv[i];
  209.         else {
  210.         c = *ap++;            /* Option byte        */
  211.         if (islower(c))            /* Normalize case    */
  212.             c = toupper(c);
  213.         switch (c) {            /* Command character    */
  214. #if !OK_STDC
  215.         case 'A':            /* Define __STDC__    */
  216.             define_builtin("__STDC__", NULL, "1");
  217.             break;
  218. #endif
  219.  
  220.         case 'C':            /* Keep comments    */
  221.             cflag = TRUE;
  222.             keepcomments = TRUE;
  223.             break;
  224.  
  225.         case 'D':            /* Define symbol    */
  226. #if (HOST != SYS_UNIX && HOST != SYS_XENIX && HOST != SYS_OS2 && HOST != SYS_MVS)
  227.             zap_uc(ap);            /* Force define to U.C.    */
  228. #endif
  229.             /*
  230.              * If the option is just "-Dfoo", make it -Dfoo=1
  231.              */
  232.             while (*ap != EOS && *ap != '=')
  233.             ap++;
  234.             if (*ap == EOS)
  235.             ap = "1";
  236.             else
  237.             *ap++ = EOS;
  238.             /*
  239.              * Now, save the word and its definition.
  240.              */
  241.             dp = defendel(argv[i] + 2, FALSE);
  242.             dp->repl = savestring(ap);
  243.             dp->nargs = DEF_NOARGS;
  244.             break;
  245.  
  246.         case 'E':            /* Ignore non-fatal    */
  247.             eflag = TRUE;        /* errors.        */
  248.             break;
  249.  
  250.         case 'G':            /* Cmpiler's debug switch */
  251.             break;
  252.  
  253.         case 'B':            /* Sun's ignore // comments */
  254.             break;
  255.  
  256.         case 'I':            /* Include directory    */
  257.             if (incend >= &incdir[MAXINCLUDE])
  258.             cfatal("Too many include directories", NULLST);
  259.             *incend++ = ap;
  260.             break;
  261.  
  262.         case 'N':            /* No predefineds    */
  263.             nflag++;            /* Repeat to undefine    */
  264.             break;            /* __LINE__, etc.    */
  265.  
  266. #if (HOST == SYS_OS2)
  267.         case 'M':
  268.             c = islower(*ap) ? toupper(*ap) : *ap;
  269.             switch (c) {
  270.             case 'T':
  271.             case 'S':
  272.                 ap = "*2,2,2,2,2,2,2,2";
  273.                 break;
  274.             case 'M':
  275.                 ap = "*2,2,2,2,2,2,4,2";
  276.                 break;
  277.             case 'C':
  278.                 ap = "*4,4,4,4,4,4,2,4";
  279.                 break;
  280.             case 'L':
  281.             case 'V':
  282.             case 'R':
  283.                 ap = "*4,4,4,4,4,4,4,4";
  284.                 break;
  285.             default:
  286.                 cwarn("Unknown model \"%s\"", arg);
  287.                 fprintf(stderr, "The following models are valid:\n\
  288.   -MT\t.COM (small) code and data\n\
  289.   -MS\tSmall code and data (default)\n\
  290.   -MC\tSmall code, large data\n\
  291.   -MM\tLarge code, small data\n\
  292.   -ML\tLarge code and data\n\
  293.   -MV\tVCM (large) code, large data\n\
  294.   -MR\tDOS16M (large) code and data\n");
  295.                 ap = NULL;
  296.                 break;
  297.             }
  298.         if (ap == NULL)
  299.             break;
  300.         /* fall through */
  301. #endif
  302.  
  303.         case 'S':
  304.             sizp = size_table;
  305.             if (isdatum = (*ap != '*'))    /* If it's just -S,    */
  306.             endtest = T_FPTR;    /* Stop here        */
  307.             else {            /* But if it's -S*    */
  308.             ap++;            /* Step over '*'    */
  309.             endtest = 0;        /* Stop at end marker    */
  310.             }
  311.             while (sizp->bits != endtest && *ap != EOS) {
  312.             if (!isdigit(*ap)) {    /* Skip to next digit    */
  313.                 ap++;
  314.                 continue;
  315.             }
  316.             size = 0;        /* Compile the value    */
  317.             while (isdigit(*ap)) {
  318.                 size *= 10;
  319.                 size += (*ap++ - '0');
  320.             }
  321.             if (isdatum)
  322.                 sizp->size = size;    /* Datum size        */
  323.             else
  324.                 sizp->psize = size;    /* Pointer size        */
  325.             sizp++;
  326.             }
  327.             if (sizp->bits != endtest)
  328.             cwarn("-S, too few values specified in %s", argv[i]);
  329.             else if (*ap != EOS)
  330.             cwarn("-S, too many values, \"%s\" unused", ap);
  331.             break;
  332.  
  333.         case 'U':            /* Undefine symbol    */
  334. #if (HOST != SYS_UNIX && HOST != SYS_XENIX && HOST != SYS_OS2 && HOST != SYS_MVS)
  335.             zap_uc(ap);
  336. #endif
  337.             if (defendel(ap, TRUE) == NULL)
  338.             cwarn("\"%s\" wasn't defined", ap);
  339.             break;
  340.  
  341.         case 'X':            /* Debug        */
  342.             debug = (isdigit(*ap)) ? atoi(ap) : 1;
  343. #if DEBUG
  344. #if (HOST == SYS_VMS || HOST == SYS_UNIX || HOST == SYS_XENIX || HOST == SYS_OS2)
  345.             signal(SIGINT, abort);    /* Trap "interrupt"    */
  346. #endif
  347. #endif
  348.             fprintf(stderr, "Debug set to %d\n", debug);
  349.             break;
  350.  
  351.         default:            /* What is this one?    */
  352.             cwarn("Unknown option \"%s\"", arg);
  353.             fprintf(stderr, "The following options are valid:\n\
  354.   -C\t\t\tWrite source file comments to output\n\
  355.   -Dsymbol=value\tDefine a symbol with the given (optional) value\n\
  356.   -Idirectory\t\tAdd a directory to the #include search list\n\
  357.   -N\t\t\tDon't predefine target-specific names\n\
  358.   -Stext\t\tSpecify sizes for #if sizeof\n\
  359.   -Usymbol\t\tUndefine symbol\n\
  360.   -Xvalue\t\tSet internal debug flag\n");
  361. #if !OK_STDC
  362.             fprintf(stderr, "\
  363.   -A\t\t\tPredefine __STDC__ for ANSI compilers\n");
  364. #endif
  365. #if (HOST == SYS_OS2)
  366.             fprintf(stderr, "\
  367.   -Mmodel\t\tSpecify memory model for #if sizeof\n");
  368. #endif
  369.             break;
  370.         }            /* Switch on all options    */
  371.         }                /* If it's a -option        */
  372.     }                /* For all arguments        */
  373.     if (j > 3) {
  374.         cerror(
  375.         "Too many file arguments.  Usage: cpp [input [output]]",
  376.         NULLST);
  377.     }
  378.     return (j);            /* Return new argc        */
  379. }
  380.  
  381. #if (HOST != SYS_UNIX && HOST != SYS_XENIX && HOST != SYS_OS2 && HOST != SYS_MVS)
  382. FILE_LOCAL
  383. zap_uc(ap)
  384. register char    *ap;
  385. /*
  386.  * Dec operating systems mangle upper-lower case in command lines.
  387.  * This routine forces the -D and -U arguments to uppercase.
  388.  * It is called only on cpp startup by dooptions().
  389.  */
  390. {
  391.     while (*ap != EOS) {
  392.         /*
  393.          * Don't use islower() here so it works with Multinational
  394.          */
  395.         if (*ap >= 'a' && *ap <= 'z')
  396.         *ap = toupper(*ap);
  397.         ap++;
  398.     }
  399. }
  400. #endif
  401.  
  402. define_builtin (name, function, replacement)
  403.      char *name;
  404.      void (*function)();
  405.      char *replacement;
  406. {
  407.   DEFBUF *dp;
  408.   dp = defendel(name, FALSE);
  409.   dp->repl = replacement;
  410.   dp->expander = function;
  411.   dp->nargs = (function == NULL) ? DEF_NOARGS : DEF_BUILTIN;
  412. }
  413.  
  414. static char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  415.                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",};
  416.  
  417. initdefines()
  418. /*
  419.  * Initialize the built-in #define's.  There are two flavors:
  420.  *     #xomdefine decus    1        (static definitions)
  421.  *    #define    __FILE__ ??        (dynamic, evaluated by magic)
  422.  * Called only on cpp startup.
  423.  *
  424.  * Note: the built-in static definitions are supressed by the -N option.
  425.  * __LINE__, __FILE__, and __DATE__ are always present.
  426.  */
  427. {
  428.     register char        **pp;
  429.     register char        *tp;
  430.     register DEFBUF        *dp;
  431.     struct tm        *tvec;
  432.     /*
  433.      * Predefine the built-in symbols.  Allow the
  434.      * implementor to pre-define a symbol as "" to
  435.      * eliminate it.
  436.      */
  437.     if (nflag == 0) {
  438.         for (pp = preset; *pp != NULL; pp++) {
  439.         if (*pp[0] != EOS) {
  440.             dp = defendel(*pp, FALSE);
  441.             dp->repl = savestring("1");
  442.             dp->nargs = DEF_NOARGS;
  443.         }
  444.         }
  445.     }
  446.  
  447.     if (nflag < 2) {
  448.  
  449.       define_builtin("__LINE__", expand_line, "");
  450.       define_builtin("__FILE__", expand_file, "");
  451. #if OK_STDC
  452.       define_builtin("__STDC__", NULL, "1");
  453. #endif
  454. #if OK_DATE
  455.       /*
  456.        * Define __DATE__ as today's date.
  457.        */
  458.       { time_t clock = time(NULL);
  459.         tvec = localtime(&clock);}
  460.       tp = getmem(12);
  461.       /* strftime(tp, 12, "%b %d %Y", tp); */
  462.       sprintf(tp, "%s %02d %04d",
  463.           months[tvec->tm_mon],
  464.           tvec->tm_mday,
  465.           tvec->tm_year + 1900);
  466.       define_builtin( "__DATE__", NULL, tp);
  467.  
  468.       tp = getmem(9);
  469.       /* strftime(tp, 9, "%H:%M:%S", tp); */
  470.       sprintf(tp, "%02d:%02d:%02d",
  471.           tvec->tm_hour,
  472.           tvec->tm_min,
  473.           tvec->tm_sec);
  474.       define_builtin( "__TIME__", NULL, tp);
  475. #endif
  476. #ifdef COOL
  477.       define_builtin("DEFPACKAGE", define_package, "");
  478. #endif
  479.     }
  480. }
  481.  
  482. #if HOST == SYS_VMS
  483. /*
  484.  * getredirection() is intended to aid in porting C programs
  485.  * to VMS (Vax-11 C) which does not support '>' and '<'
  486.  * I/O redirection.  With suitable modification, it may
  487.  * useful for other portability problems as well.
  488.  */
  489.  
  490. int
  491. getredirection(argc, argv)
  492. int        argc;
  493. char        **argv;
  494. /*
  495.  * Process vms redirection arg's.  Exit if any error is seen.
  496.  * If getredirection() processes an argument, it is erased
  497.  * from the vector.  getredirection() returns a new argc value.
  498.  *
  499.  * Warning: do not try to simplify the code for vms.  The code
  500.  * presupposes that getredirection() is called before any data is
  501.  * read from stdin or written to stdout.
  502.  *
  503.  * Normal usage is as follows:
  504.  *
  505.  *    main(argc, argv)
  506.  *    int        argc;
  507.  *    char        *argv[];
  508.  *    {
  509.  *        argc = getredirection(argc, argv);
  510.  *    }
  511.  */
  512. {
  513.     register char        *ap;    /* Argument pointer    */
  514.     int            i;    /* argv[] index        */
  515.     int            j;    /* Output index        */
  516.     int            file;    /* File_descriptor     */
  517.     extern int        errno;    /* Last vms i/o error     */
  518.  
  519.     for (j = i = 1; i < argc; i++) {   /* Do all arguments    */
  520.         switch (*(ap = argv[i])) {
  521.         case '<':            /* <file        */
  522.         if (freopen(++ap, "r", stdin) == NULL) {
  523.             perror(ap);        /* Can't find file    */
  524.             exit(errno);    /* Is a fatal error    */
  525.         }
  526.         break;
  527.  
  528.         case '>':            /* >file or >>file    */
  529.         if (*++ap == '>') {    /* >>file        */
  530.             /*
  531.              * If the file exists, and is writable by us,
  532.              * call freopen to append to the file (using the
  533.              * file's current attributes).  Otherwise, create
  534.              * a new file with "vanilla" attributes as if the
  535.              * argument was given as ">filename".
  536.              * access(name, 2) returns zero if we can write on
  537.              * the specified file.
  538.              */
  539.             if (access(++ap, 2) == 0) {
  540.             if (freopen(ap, "a", stdout) != NULL)
  541.                 break;    /* Exit case statement    */
  542.             perror(ap);    /* Error, can't append    */
  543.             exit(errno);    /* After access test    */
  544.             }            /* If file accessable    */
  545.         }
  546.         /*
  547.          * On vms, we want to create the file using "standard"
  548.          * record attributes.  creat(...) creates the file
  549.          * using the caller's default protection mask and
  550.          * "variable length, implied carriage return"
  551.          * attributes. dup2() associates the file with stdout.
  552.          */
  553.         if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
  554.          || dup2(file, fileno(stdout)) == -1) {
  555.             perror(ap);        /* Can't create file    */
  556.             exit(errno);    /* is a fatal error    */
  557.         }            /* If '>' creation    */
  558.         break;            /* Exit case test    */
  559.  
  560.         default:
  561.         argv[j++] = ap;        /* Not a redirector    */
  562.         break;            /* Exit case test    */
  563.         }
  564.     }                /* For all arguments    */
  565.     argv[j] = NULL;            /* Terminate argv[]    */
  566.     return (j);            /* Return new argc    */
  567. }
  568. #endif
  569.  
  570.  
  571.